package com.mallcloud.mall.admin.config;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.Query;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mallcloud.mall.common.core.util.R;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 请求操作日志
 */
@Slf4j
@Aspect
@Service
public class RequestLogAspect {

	@Pointcut("execution(* com.mallcloud.mall.*.controller.*Controller.*(..))")
	public void pointCut() { }

	@SneakyThrows
	@Around("pointCut()")
	public Object beforePointCut(ProceedingJoinPoint point) {
		MethodSignature signature = (MethodSignature) point.getSignature();
		Method method = signature.getMethod();
		ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
		if(Objects.isNull(apiOperation)){
			return point.proceed();
		}
		String methodName = apiOperation.value();

		try {
			log.debug("解析对象");// 如果栈溢出，可以看到原因
			String s = JSONUtil.toJsonStr(write(point.getArgs()));

			log.info("--> {},{},请求参数:{}",
					methodName,
					StrUtil.format("{}.{}", point.getTarget().getClass().getName(), point.getSignature().getName()),
					s
			);
		}
		catch (Exception e) {
		}
		Object proceed = point.proceed();
		if(Objects.isNull(proceed)) return null;
		try {
			if (proceed instanceof R && ((R) proceed).getData() instanceof IPage) {
				R r = (R) proceed;
				IPage page = (IPage) r.getData();
				log.info("<-- {\"msg\":\"{}\",\"id\":{},\"data\":\"{}\"}\n",
						r.getCode(),
						r.getMsg(),
						MapUtil.builder(new HashMap<String, Object>())
								.put("records", JSONUtil.toJsonStr(page.getRecords()))
								.put("total", page.getTotal())
								.put("current", page.getPages())
								.put("size", page.getSize()).build());
			} else {
				log.info("<-- {}\n",
						JSONUtil.toJsonStr(proceed));
			}
		}
		catch (Exception e) {
		}
		return proceed;
	}

	public Object write(Object o) {
		if (o instanceof Page ||
				o instanceof Query ||
				o instanceof HttpServletResponse ||
				o instanceof HttpServletRequest ||
				o instanceof MultipartFile
		) {
			o = null;
		}
		else if (o instanceof Map) {
			o = ((Map<String, ?>) o).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> write(v.getValue())));
		}
		else if (o instanceof List) {
			o = ((List) o).stream().map(o1 -> write(o1)).collect(Collectors.toList());
		}
		else if (o instanceof Object[]) {
			List temp = new ArrayList();
			for (Object o1 : (Object[]) o) {
				temp.add(write(o1));
			}
			o = temp;
		}
		return o;
	}
}
